package com.authorization;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.authentication.LoginSuccessAuthentication;
import com.authentication.RBACUser;
import com.authorization.storage.AuthorityStorageManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;

import static com.common.Constant.JWT_DEPT_ID;
import static com.common.Constant.JWT_USER_ID;

/**
 * 负责把请求头中的 Authorization token 解析为完整的 {@link Authentication} 对象，
 * 并设置到 {@link SecurityContextHolder} 中
 */
public class TokenParserFilter extends OncePerRequestFilter {

    private final AuthorityStorageManager<GrantedAuthority> authorityStorageManager;

    public TokenParserFilter(AuthorityStorageManager<GrantedAuthority> authorityStorageManager) {
        this.authorityStorageManager = authorityStorageManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = req.getHeader("Authorization");

        if (token == null) {
            return;
        }

        DecodedJWT decodedJWT;
        try {
            Algorithm algorithm = Algorithm.none();
            JWTVerifier verifier = JWT.require(algorithm)
                    // specify an specific claim validations
//                    .withIssuer("auth0")
                    // reusable verifier instance
                    .build();

            decodedJWT = verifier.verify(token);
        } catch (JWTVerificationException exception) {
            // Invalid signature/claims
            return;
        }

        Claim claim = decodedJWT.getClaim(JWT_USER_ID);
        RBACUser rbacUser = new RBACUser(
                decodedJWT.getIssuer(),
                claim.asLong(),
                decodedJWT.getClaim(JWT_DEPT_ID).asLong()
        );

        LoginSuccessAuthentication loginSuccessAuthentication = new LoginSuccessAuthentication(
                null,
                rbacUser,
                null
        );

        Collection<GrantedAuthority> authorities = authorityStorageManager.load(loginSuccessAuthentication);



        SecurityContextHolder.getContext().setAuthentication(new LoginSuccessAuthentication(
                null,
                rbacUser,
                authorities
        ));

        filterChain.doFilter(req, response);
    }
}
